package ru.yelbota.flex.as3jobs {

import flash.events.Event;

import ru.yelbota.flex.as3jobs.exceptions.JobSimpleResourceException;

import ru.yelbota.flex.as3jobs.exceptions.JobWaitEventException;

use namespace as3_jobs;

public class Job {

	private static var lastJobId:uint = 0;
    private static var currentJobId:uint = 0;

    private static const jobs:Vector.<Function> = new Vector.<Function>();
    private static const jobResources:Vector.<Object> = new Vector.<Object>();
    private static const jobCallIndex:Vector.<int> = new Vector.<int>();

    [Lambda(returnType="void")]

    public static function start(job:Function):void {
        jobs.push(job);
        jobResources.push(new Object)
        currentJobId = lastJobId++;
        restart(currentJobId);
    }

    private static function restart(jobId:uint):void {
        const job:Function = jobs[jobId];
        currentJobId = jobId;
        jobCallIndex[jobId] = 0;

        try {
            job();

            delete jobs[jobId];
            delete jobResources[jobId];
            delete jobCallIndex[jobId];
        }
        catch (e:JobSimpleResourceException) {
            // TODO remove this.
            var resources:Object = jobResources[jobId];
            resources[e.resourceId] = e.resource;
            restart(jobId);
        }
        catch (e:JobWaitEventException) {
            resources = jobResources[jobId];
            resources[e.resourceId] = e.target;
            e.target.addEventListener(e.eventName, function(event:Event):void {
                restart(jobId);
            });
        }
    }

    as3_jobs static function getResource(jobId:uint, resourceId:String):Object {
        var resources:Object = jobResources[jobId];
        if (resources != null) return resources[resourceId];
        else return null;
    }

    as3_jobs static function getResourceOrElse(jobId:uint, resourceId:String, orElse:Function):Object {
        const resource:Object = getResource(jobId, resourceId);

        if (resource == null) {
            const orElseResult:Object = orElse();
            jobResources[jobId][resourceId] = orElseResult;
            return orElseResult;
        }
        else return resource;
    }

    as3_jobs static function getCurrentJob():uint {
        return currentJobId;
    }

    as3_jobs static function getCurrentCallIndex():uint {
       return jobCallIndex[currentJobId];
    }

    as3_jobs static function incrementCallIndex():void {
        jobCallIndex[currentJobId]++;
    }


}

}
